package com.campus.runrun.serviceImpl;



import com.campus.runrun.common.exception.CustomException;
import com.campus.runrun.common.exception.ResultCodeEnum;
import com.campus.runrun.common.shiro.JWTUtil;
import com.campus.runrun.common.utils.HttpUtil;
import com.campus.runrun.common.utils.JSONUtil;
import com.campus.runrun.model.dto.UserJwtDTO;
import com.campus.runrun.model.entity.UserEntity;
import com.campus.runrun.model.vo.Code2SessionResponse;
import com.campus.runrun.model.vo.UserLoginReqVO;
import com.campus.runrun.model.vo.UserVO;
import com.campus.runrun.service.api.LoginService;
import com.campus.runrun.service.api.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.net.URI;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class LoginServiceImpl implements LoginService {

    /**
     * 普通用户（小程序端）的用的的角色id
     */
    private static final   Integer MINI_PROGRAM_ROLE_ID = 1;

    @Value("${wx.app_id}")
    private String appId;

    @Value("${wx.app_secret}")
    private String appSecret;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private UserService userService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    @Transactional
    public UserVO wxMiniProGramLogin(UserLoginReqVO userLoginReqVO) {
        // code2session接口返回JSON数据
        String resultJson = code2Session(userLoginReqVO.getCode());
        log.info("code2session接口返回JSON数据{}", resultJson);
        // 解析数据
        Code2SessionResponse response = JSONUtil.toJavaObject(resultJson, Code2SessionResponse.class);

        if (!"0".equals(response.getErrcode())) {
            // 请求失败
            throw new CustomException(ResultCodeEnum.CODE2SESSION_ERROR);
        }

        String openId = response.getOpenid();
        // String sessionKey = response.getSession_key();
        UserEntity userEntity = userService.getUserByOpenId(openId);

        // 用户不存在则存入数据库
        if (userEntity == null) {
            userEntity = this.saveUser(openId, userLoginReqVO.getUsername());
        }

        // JWT返回自定义登录态token并把token缓存到redis中
        Integer userId = userEntity.getId();
        // 设置用户名
        UserJwtDTO userJwtDTO = new UserJwtDTO();
        userJwtDTO.setId(userId);
        userJwtDTO.setOpenId(openId);
        userJwtDTO.setUsername(userEntity.getUsername());
        String token = JWTUtil.createTokenByWxAccount(userJwtDTO);
        // redis缓存JWT,并设置过期时间
        String jwtId = "runrun_user_token:" + Integer.toString(userId);
        redisTemplate.opsForValue().set(jwtId, token, JWTUtil.EXPIRE_TIME, TimeUnit.SECONDS);

        log.info("JWT返回自定义登录态token[{}]，并把token缓存到redis中", token);
        // 封装放回结果对象
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(userEntity, userVO);
        userVO.setToken(token);
        return userVO;
    }

    /**
     * 判断用户是否存存在
     * @param openId
     * @param username
     * @return
     */
    @Transactional
    public UserEntity saveUser(String openId, String username) {
        // 若不存在则新建用户插入到数据库
        UserEntity newUserEntity = new UserEntity();
        newUserEntity.setOpenId(openId);
        newUserEntity.setUsername(username);
        userService.save(newUserEntity);
        return newUserEntity;
    }

    /**
     * 微信官方API：code2session
     * 用户获取微信用户的openId和sessionKey
     *
     * @param code
     * @return
     */
    private String code2Session(String code) {
        String code2SessionUrl = "https://api.weixin.qq.com/sns/jscode2session";
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("appid", appId);
        params.add("secret", appSecret);
        params.add("js_code", code);
        params.add("grant_type", "authorization_code");
        log.info("开始请求微信登录接口，获取openid和sessionkey");
        URI code2Session = HttpUtil.getUriWithParams(code2SessionUrl, params);
        return restTemplate.exchange(code2Session, HttpMethod.GET, new HttpEntity<String>(new HttpHeaders()),
                String.class).getBody();
    }




}